import lombok.AllArgsConstructor;
import lombok.Data;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.commons.lang3.time.DateFormatUtils;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 各种oom  情况模拟
 *
 * VM参数: -Xms10m -Xmx10m -Xss160k -XX:+PrintGCDetails -XX:SurvivorRatio=8
 * -XX:+PrintHeapAtGC GC 前后打印GC
 * -XX:+HeapDumpOnOutOfMemoryError 当JVM发生OOM时,自动生成DUMP文件
 * -XX:HeapDumpPath=~/work/public/bold/
 * -Xloggc:~/work/public/bold/gc.log 日志
 *
 * -XX:MetaspaceSize=10m
 *
 *
 * @author khaiLoon
 * @date 2018/12/18
 **/
@SuppressWarnings("all")
public class OOM {
    public static void main(String[] args) throws Exception {

        //堆内
        //test1();

        //堆外
        //test3();

        //元数据
        test2();

        //栈空间不足 StackOverflowError
//        test4(1);

        //测试垃圾回收详情
//        test5();

//        TimeUnit.SECONDS.sleep(10);
    }

    private static void test5() throws Exception {
        /**
         * VM参数: -Xms10m -Xmx10m -Xss160k -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+PrintHeapAtGC
         * -XX:+PrintHeapAtGC GC 前后打印GC
         * -Xloggc:/work/public/bold/early/src/main/java/gc.log 日志
         *
         * 如何 一次 GC 不发生利用最大内存
         * 1 mb = 1024 kb = 1024 * 1024 byte
         */
        int _1MB = 1024 * 1024;
        byte[] allocation1, allocation2;
        allocation1 = new byte[6 * _1MB];
//        allocation1 = new byte[2 * _1MB];
//        allocation2 = new byte[12 * _1MB];


        //日志分析 https://juejin.im/post/5cdd529251882568ad345c1a


        // [GC (Allocation Failure) [PSYoungGen: 4771K->480K(6144K)] 5173K->5089K(19968K), 0.0028584 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
        // 4771K->480K(6144K)   新生代 -> 新生代 （新生代总）
        // 5173K->5089K(19968K) 堆 -> 堆 (堆总)
        // 0.0028584 secs Gc 耗时

        // [Full GC (Ergonomics) [PSYoungGen: 6112K->0K(6144K)] [ParOldGen: 8705K->11659K(13824K)] 14817K->11659K(19968K), [Metaspace: 4006K->4006K(1056768K)], 0.0059238 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
        // 6112K->0K(6144K) 新生代 -> 新生代 （新生代总）
        // 8705K->11659K(13824K)  老年代 -> 老年代 （老年代总）
        // 14817K->11659K(19968K) 堆 -> 堆 (堆总)
    }


    public static void test1() {
        while (true) {
            List<AVO> list = new ArrayList<>(10000);
            while (true) {
                list.add(new AVO(System.currentTimeMillis()+""));
            }
        }
    }

    public static void test2() {
        class OOMObject {
        }
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            enhancer.create();
        }
    }

    public static void test3() throws IllegalAccessException {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(1024 * 1024);
        }

    }

    private static void test4(long i) {
        System.out.println(++i);
        test4(i);
    }


    @Data
    @AllArgsConstructor
    public static class AVO {
        private String a;
    }

}
